import argparse

import yaml
import os
from typing import Any, Optional
from threading import Lock

from dotenv import load_dotenv

class AppConfig:
    _instance: Optional["AppConfig"] = None
    _lock: Lock = Lock()

    def __init__(self, config_path: str):
        if not os.path.exists(config_path):
            raise FileNotFoundError(f"Config file not found: {config_path}")
        with open(config_path, 'r', encoding='utf-8') as f:
            self.config_data = yaml.safe_load(f)

    @classmethod
    def load(cls, config_path: str):
        with cls._lock:
            if cls._instance is None:
                cls._instance = cls(config_path)
        return cls._instance

    @classmethod
    def instance(cls) -> "AppConfig":
        if cls._instance is None:
            raise RuntimeError("AppConfig has not been loaded. Call AppConfig.load(path) first.")
        return cls._instance

    def get(self, key: str, default: Any = None) -> Any:
        keys = key.split(".")
        data = self.config_data
        for k in keys:
            if isinstance(data, dict):
                data = data.get(k, default)
            else:
                return default
        return data


# 获取配置
def get_config(key: str, default=None):
    try:
        return AppConfig.instance().get(key, default)
    except RuntimeError:
        raise RuntimeError("配置未初始化，请确保主程序中已调用 AppConfig.load(config_path)")


# 命令行参数解析
def parse_args():
    # 创建解析器
    parser = argparse.ArgumentParser(
        description="一个命令行参数解析示例",
        epilog="示例: python script.py --config config_default.yaml"
    )
    # 添加参数
    parser.add_argument("--config", required=False, help="配置文件路径")
    # 解析参数并转为字典
    args = parser.parse_args()
    return vars(args)  # 转换为字典



# 初始化系统参数
def init_app_config():
    """
    初始化系统参数
    :param config_path:
    :return:
    """
    load_dotenv()
    # 获取系统环境变量
    config_path = os.environ.get("CONFIG_PATH")
    # 获取命令行参数
    args_dict = parse_args()
    if args_dict["config"]:
        config_path = args_dict["config"]
    # 获取配置路径
    if config_path is None:
        raise RuntimeError("必须在环境变量中设置 CONFIG_PATH,或在启动命令中指定 --config 参数")
    # 加载配置
    app_config = AppConfig.load(config_path).instance()
    return app_config